﻿using FastApi.Attributes;
using Namotion.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NJsonSchema;
using NJsonSchema.Generation;
using NSwag;
using System.Collections;
using System.IO.Compression;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;

namespace FastApi.Swag
{
    public class FastSwag
    {
        #region private static

        private static bool IsSimpleType(Type type)
        {
            if (type == typeof(string) || type == typeof(char) || type == typeof(char?))
            {
                return true;
            }
            if (type == typeof(int) || type == typeof(int?) || type == typeof(uint) || type == typeof(uint?))
            {
                return true;
            }
            if (type == typeof(long) || type == typeof(long?) || type == typeof(ulong) || type == typeof(ulong?))
            {
                return true;
            }
            if (type == typeof(DateTime) || type == typeof(DateTime?))
            {
                return true;
            }
            if (type == typeof(bool) || type == typeof(bool?))
            {
                return true;
            }
            if (type == typeof(decimal) || type == typeof(decimal?))
            {
                return true;
            }
            if (type == typeof(double) || type == typeof(double?))
            {
                return true;
            }
            if (type == typeof(float) || type == typeof(float?))
            {
                return true;
            }
            if (type == typeof(DateTimeOffset) || type == typeof(DateTimeOffset?))
            {
                return true;
            }
            if (type == typeof(short) || type == typeof(short?) || type == typeof(ushort) || type == typeof(ushort?))
            {
                return true;
            }
            if (type == typeof(byte) || type == typeof(byte?) || type == typeof(sbyte) || type == typeof(sbyte?))
            {
                return true;
            }
            if (type == typeof(Enum))
            {
                return true;
            }
            if (type == typeof(Guid) || type == typeof(Guid?))
            {
                return true;
            }
            if (type == typeof(TimeSpan) || type == typeof(TimeSpan?))
            {
                return true;
            }
            if (type == typeof(DateOnly) || type == typeof(DateOnly?))
            {
                return true;
            }
            if (type == typeof(TimeOnly) || type == typeof(TimeOnly?))
            {
                return true;
            }
            return false;
        }

        private static bool IsArray(Type t)
        {
            if (IsSimpleType(t))
            {
                return false;
            }

            if (t.Name == typeof(IAsyncEnumerable<>).Name)
            {
                return true;
            }

            return t.IsArray || typeof(IList).IsAssignableFrom(t) || typeof(IEnumerable).IsAssignableFrom(t)
                || typeof(Array).IsAssignableFrom(t) || typeof(ArrayList).IsAssignableFrom(t);
        }

        private static Type GetArrayType(Type t)
        {
            if (IsSimpleType(t))
            {
                return t;
            }

            if (t.Name == typeof(IAsyncEnumerable<>).Name)
            {
                return t.GenericTypeArguments[0];
            }

            if (t.IsArray || typeof(IList).IsAssignableFrom(t) || typeof(ArrayList).IsAssignableFrom(t) || typeof(IEnumerable).IsAssignableFrom(t))
            {
                var tVal = t.GenericTypeArguments.FirstOrDefault();
                if (tVal != null)
                {
                    return tVal;
                }
                else if (t != typeof(JsonNode) && t != typeof(JsonArray) && t != typeof(JsonObject) && t != typeof(JsonValue))
                {
                    return t.GetElementType();
                }
            }

            return t;
        }


        #endregion

        /// <summary>
        /// api分组
        /// </summary>
        private readonly Dictionary<string, Dictionary<string, FastModule>> groupDict = new()
        {
            { "default", new Dictionary<string, FastModule>()}
        };

        public event Action<OpenApiDocument> OnCreateDocument;

        public event Action<JsonSchemaGeneratorSettings> OnSettings;

        public event Func<JsonSchema, JsonSchema> OnResponse;

        public bool WriteIndented { get; set; } = false;

        public FastSwagVersion Version { get; set; } = FastSwagVersion.V40;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dict">路由字典</param>
        public FastSwag(Dictionary<string, FastModule> dict)
        {
            //分组处理
            foreach (var item in dict)
            {
                var groupName = item.Value.SwaggerGroup;
                if (string.IsNullOrEmpty(groupName))
                {
                    groupName = item.Value.Type.ToContextualType().GetXmlDocsTag("swag-group");
                }

                if (string.IsNullOrEmpty(groupName))
                {
                    groupName = "default";
                }

                var ok = groupDict.TryGetValue(groupName, out var val);
                if (!ok)
                {
                    val = new Dictionary<string, FastModule>();
                    groupDict.Add(groupName, val);
                }
                val.Add(item.Key, item.Value);
            }
        }

        private static List<FastSwagPar> CreatePar(string str, OpenApiParameterKind kind)
        {
            var list = new List<FastSwagPar>();
            if (string.IsNullOrEmpty(str))
            {
                return list;
            }

            try
            {

                var array = str.Trim().Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var item in array)
                {
                    var model = new FastSwagPar
                    {
                        Kind = kind,
                    };

                    var array2 = item.Trim().Split('@', StringSplitOptions.RemoveEmptyEntries);
                    if (array2.Length > 1)
                    {
                        model.Description = array2[1];
                    }

                    var array3 = array2[0].Split('.', StringSplitOptions.RemoveEmptyEntries);
                    model.Name = array3[0];

                    if (array3.Length >= 2) //拥有类型
                    {
                        var t = array3[1];
                        if (t == "number" || t == "double" || t == "float" || t == "decimal")
                        {
                            model.ObjectType = JsonObjectType.Number;
                            model.CsType = typeof(decimal);
                        }
                        else if (t == "double")
                        {
                            model.ObjectType = JsonObjectType.Number;
                            model.CsType = typeof(double);
                        }
                        else if (t == "float")
                        {
                            model.ObjectType = JsonObjectType.Number;
                            model.CsType = typeof(float);
                        }
                        else if (t == "decimal")
                        {
                            model.ObjectType = JsonObjectType.Number;
                            model.CsType = typeof(decimal);
                        }
                        else if (t == "bool")
                        {
                            model.ObjectType = JsonObjectType.Boolean;
                            model.CsType = typeof(bool);
                        }
                        else if (t == "int")
                        {
                            model.ObjectType = JsonObjectType.Integer;
                            model.CsType = typeof(int);
                        }
                        else if (t == "long")
                        {
                            model.ObjectType = JsonObjectType.Integer;
                            model.CsType = typeof(long);
                        }
                        else if (t == "file")
                        {
                            model.ObjectType = JsonObjectType.File;
                        }
                        else
                        {
                            model.ObjectType = JsonObjectType.String;
                            model.CsType = typeof(string);
                        }
                    }

                    if (array3.Length == 3)
                    {
                        model.IsRequired = Convert.ToBoolean(array3[2]);
                    }

                    list.Add(model);
                }
                return list;
            }
            catch
            {
                list.Clear();
            }

            return list;

        }

        private void InitDocument(OpenApiDocument document, Dictionary<string, FastModule> dict)
        {
            var settings = new JsonSchemaGeneratorSettings();
            settings.GenerateExamples = true; //请求样例
            //settings.SchemaNameGenerator = new MySchemaName(); //Schema名字重命名
            settings.SchemaType = SchemaType.OpenApi3;
            settings.TypeMappers.Add(new MyJsonNodeMapper());
            settings.TypeMappers.Add(new MyJsonObjectMapper());
            settings.TypeMappers.Add(new MyJsonArrayMapper());
            settings.AllowReferencesWithProperties = true;
            OnSettings?.Invoke(settings);

            var generator = new JsonSchemaGenerator(settings);
            var resolver = new OpenApiSchemaResolver(document, settings);

            dict = dict.OrderBy(b => b.Key).ToDictionary(el => el.Key, el => el.Value);

            //遍历类
            foreach (var keyPar in dict)
            {
                var module = keyPar.Value;

                var tagName = module.RouteName.Trim('/').Replace("/", "-");
                document.Tags.Add(new OpenApiTag
                {
                    Name = tagName,
                    Description = module.Type.ToContextualType().GetXmlDocsSummary() //类描述
                });

                //遍历类方法
                foreach (var keyPar2 in module.ActionDict)
                {
                    var action = keyPar2.Value;

                    if (action.ActionType == FastActionType.View)
                    {
                        continue;
                    }

                    var contextMentodType = module.Type.ToContextualType().Methods.FirstOrDefault(f => f.Name == action.MethodName);
                    var pathItem = new OpenApiPathItem();
                    var opt = new OpenApiOperation
                    {
                        Tags = new List<string>() { tagName },
                        RequestBody = new()
                    };

                    var formData = new JsonSchema
                    {
                        Type = JsonObjectType.Object
                    };

                    if (action.IsForm)
                    {
                        opt.RequestBody.Content.TryAdd("multipart/form-data", new OpenApiMediaType { Schema = formData });
                    }

                    //Path
                    if (!string.IsNullOrEmpty(action.PathName))
                    {
                        var p = new OpenApiParameter
                        {
                            Kind = OpenApiParameterKind.Path,
                            Name = action.PathName,
                            Schema = new JsonSchema { Type = JsonObjectType.String },
                            IsRequired = true,
                            Description = "path to url"
                        };
                        opt.Parameters.Add(p);
                    }

                    //自定义query参数
                    var queryStr = contextMentodType.GetXmlDocsTag("swag-query") ?? "";
                    var queryParList = CreatePar(queryStr, OpenApiParameterKind.Query);
                    foreach (var item in queryParList)
                    {
                        var p = new OpenApiParameter
                        {
                            Kind = item.Kind,
                            Name = item.Name,
                            Schema = generator.Generate(item.CsType.ToContextualType(), resolver),
                            IsRequired = item.IsRequired,
                            Description = item.Description
                        };
                        opt.Parameters.Add(p);
                    }

                    //自定义form参数
                    var formStr = contextMentodType.GetXmlDocsTag("swag-form") ?? "";
                    var formParList = CreatePar(formStr, OpenApiParameterKind.FormData);
                    if (formParList.Count > 0)
                    {
                        opt.RequestBody.Content.TryAdd("multipart/form-data", new OpenApiMediaType { Schema = formData });
                    }
                    foreach (var item in formParList)
                    {
                        var p = new OpenApiParameter
                        {
                            Kind = item.Kind,
                            Name = item.Name,
                            Type = item.ObjectType,
                            IsRequired = item.IsRequired,
                            Description = item.Description
                        };

                        if (p.Type == JsonObjectType.File)
                        {
                            p.Schema = new JsonSchema()
                            {
                                Type = JsonObjectType.File
                            };

                            formData.Properties.Add(p.Name, new JsonSchemaProperty
                            {
                                Type = JsonObjectType.File,
                                Description = item.Description,
                                IsRequired = item.IsRequired
                            });
                        }
                        else
                        {
                            p.Schema = generator.Generate(item.CsType.ToContextualType(), resolver);
                            formData.Properties.Add(p.Name, new JsonSchemaProperty
                            {
                                Type = p.Type,
                                Description = item.Description,
                                IsRequired = item.IsRequired
                            });
                        }
                    }

                    //是否是form请求
                    var isFormAction = false;
                    if (action.IsForm || formParList.Count > 0)
                    {
                        isFormAction = true;
                    }

                    //获取reqRes特性
                    var reqResAttr = (FastReqResAttribute)action.AttributeList.FirstOrDefault(f => f is FastReqResAttribute);

                    var hasBody = false;

                    //遍历方法参数
                    foreach (var methodPar in action.ParamList)
                    {
                        if (methodPar.IsCustomerType) //如果是自定义类型，直接跳过
                        {
                            continue;
                        }

                        var contextParType = contextMentodType.Parameters.FirstOrDefault(f => f.Name == methodPar.Name);

                        if (methodPar.RequestType == FastParamType.Query || methodPar.RequestType == FastParamType.Form)
                        {
                            if (IsSimpleType(methodPar.Type))
                            {
                                var p = new OpenApiParameter();
                                p.Name = methodPar.Name;
                                p.Description = contextParType.GetXmlDocs();
                                p.Schema = generator.Generate(methodPar.Type.ToContextualType(), resolver);
                                if (methodPar.RequestType == FastParamType.Query)
                                {
                                    if (queryParList.Any(a => a.Name == p.Name))
                                    {
                                        continue;
                                    }
                                    //加进去防止重复
                                    queryParList.Add(new FastSwagPar { Name = p.Name });
                                    p.Kind = OpenApiParameterKind.Query;
                                    opt.Parameters.Add(p);
                                }
                                else
                                {
                                    if (formParList.Any(a => a.Name == p.Name))
                                    {
                                        continue;
                                    }
                                    //p.Kind = OpenApiParameterKind.FormData;
                                    //加进去防止重复
                                    formParList.Add(new FastSwagPar { Name = p.Name });
                                    formData.Properties.Add(p.Name, new JsonSchemaProperty
                                    {
                                        Type = p.Schema.Type,
                                        Description = p.Description
                                    });
                                }
                            }
                            else
                            {
                                var prototypeList = methodPar.Type.GetProperties();
                                foreach (var item in prototypeList)
                                {
                                    if (IsSimpleType(item.PropertyType))
                                    {
                                        var p = new OpenApiParameter();
                                        p.Name = item.Name;
                                        p.Description = item.GetXmlDocsSummary();
                                        p.Schema = generator.Generate(item.PropertyType.ToContextualType(), resolver);
                                        if (methodPar.RequestType == FastParamType.Query)
                                        {
                                            if (queryParList.Any(a => a.Name == p.Name))
                                            {
                                                continue;
                                            }
                                            //加进去防止重复
                                            queryParList.Add(new FastSwagPar { Name = p.Name });
                                            p.Kind = OpenApiParameterKind.Query;
                                            opt.Parameters.Add(p);
                                        }
                                        else
                                        {
                                            if (formParList.Any(a => a.Name == p.Name))
                                            {
                                                continue;
                                            }
                                            //p.Kind = OpenApiParameterKind.FormData;
                                            //加进去防止重复
                                            formParList.Add(new FastSwagPar { Name = p.Name });
                                            formData.Properties.Add(p.Name, new JsonSchemaProperty
                                            {
                                                Type = p.Schema.Type,
                                                Description = p.Description
                                            });
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            //如果是form请求，或者get请求,直接跳过
                            if (isFormAction || action.HttpMethod == "GET")
                            {
                                continue;
                            }

                            if (hasBody)
                            {
                                continue;
                            }

                            var p = new OpenApiParameter();
                            p.Kind = OpenApiParameterKind.Body;
                            p.IsRequired = true;
                            var exampleJson = contextMentodType.GetXmlDocsTag("swag-body") ?? "";

                            if (methodPar.Type == typeof(JsonObject))
                            {
                                JObject jobj; //自定义schema
                                try
                                {
                                    if (exampleJson == "")
                                    {
                                        exampleJson = "{}";
                                    }
                                    jobj = JsonConvert.DeserializeObject<JObject>(exampleJson);
                                }
                                catch
                                {
                                    jobj = JsonConvert.DeserializeObject<JObject>("{}");
                                }

                                p.Schema = new JsonSchema
                                {
                                    Example = jobj
                                };
                                opt.Parameters.Add(p);
                                hasBody = true;
                                continue;
                            }
                            else if (methodPar.Type == typeof(JsonArray))
                            {
                                JArray jarry; //自定义schema
                                try
                                {
                                    if (exampleJson == "")
                                    {
                                        exampleJson = "[]";
                                    }
                                    jarry = JsonConvert.DeserializeObject<JArray>(exampleJson);
                                }
                                catch
                                {
                                    jarry = JsonConvert.DeserializeObject<JArray>("[]");
                                }

                                p.Schema = new JsonSchema
                                {
                                    Example = jarry
                                };
                                opt.Parameters.Add(p);
                                hasBody = true;
                                continue;
                            }
                            else if (methodPar.Type == typeof(JsonNode) || methodPar.Type == typeof(string) || methodPar.Type == typeof(JsonElement))
                            {
                                JToken jtk; //自定义schema
                                try
                                {
                                    jtk = JsonConvert.DeserializeObject<JToken>(exampleJson);
                                }
                                catch
                                {
                                    jtk = JsonConvert.DeserializeObject<JToken>("");
                                }

                                p.Schema = new JsonSchema
                                {
                                    Example = jtk
                                };
                                opt.Parameters.Add(p);
                                hasBody = true;
                                continue;
                            }

                            if (!string.IsNullOrEmpty(exampleJson))
                            {
                                JToken jtk; //自定义schema
                                try
                                {
                                    jtk = JsonConvert.DeserializeObject<JToken>(exampleJson);
                                }
                                catch
                                {
                                    jtk = JsonConvert.DeserializeObject<JToken>("");
                                }

                                p.Schema = new JsonSchema
                                {
                                    Example = jtk
                                };
                                opt.Parameters.Add(p);
                                hasBody = true;
                                continue;
                            }

                            var bodyType = methodPar.Type;
                            if (reqResAttr != null && reqResAttr.ReqType != null)
                            {
                                bodyType = reqResAttr.ReqType;
                            }

                            var isArray = IsArray(bodyType);
                            var finalType = GetArrayType(bodyType);

                            if (isArray && IsSimpleType(finalType)) //是数组，又是简单类型
                            {
                                p.Schema = generator.Generate(bodyType.ToContextualType(), resolver);
                                opt.Parameters.Add(p);
                                hasBody = true;
                                continue;
                            }

                            var componentsVal = generator.Generate(finalType.ToContextualType(), resolver);

                            if (!isArray)
                            {
                                p.Schema = new JsonSchema
                                {
                                    Reference = componentsVal
                                };
                            }
                            else
                            {
                                p.Schema = new JsonSchema
                                {
                                    Type = JsonObjectType.Array,
                                    Item = new JsonSchema
                                    {
                                        Reference = componentsVal
                                    }
                                };
                            }
                            ;
                            opt.Parameters.Add(p);
                            hasBody = true;
                        }
                    }

                    if (!isFormAction && !(action.HttpMethod == "GET") && !hasBody)
                    {
                        var p = new OpenApiParameter();
                        p.Kind = OpenApiParameterKind.Body;
                        p.Schema = new JsonSchema
                        {
                            Example = null
                        };
                        opt.Parameters.Add(p);
                    }

                    #region 响应处理

                    if (action.ActionType == FastActionType.Default)
                    {
                        var resType = action.ReturnType;
                        if (action.ActionTypeTask == FastActionTypeTask.Task || action.ActionTypeTask == FastActionTypeTask.ValueTask)
                        {
                            resType = typeof(void);
                        }
                        else if (action.ActionTypeTask == FastActionTypeTask.TaskT || action.ActionTypeTask == FastActionTypeTask.ValueTaskT)
                        {
                            resType = action.ReturnType.GenericTypeArguments[0];
                        }

                        if (resType == typeof(void) || resType == typeof(object))
                        {
                            resType = typeof(string);
                        }

                        JsonSchema baseSchema = null;

                        var resExampleJson = contextMentodType.GetXmlDocsTag("swag-res") ?? "";
                        if (!string.IsNullOrEmpty(resExampleJson))
                        {
                            JToken jtk; //自定义schema
                            try
                            {
                                jtk = JsonConvert.DeserializeObject<JToken>(resExampleJson);
                                baseSchema = new JsonSchema
                                {
                                    Example = jtk
                                };
                            }
                            catch
                            {

                            }
                        }

                        if (baseSchema == null)
                        {

                            if (reqResAttr != null && reqResAttr.ResType != null)
                            {
                                resType = reqResAttr.ResType;
                            }

                            var isArray = IsArray(resType);
                            var finalType = GetArrayType(resType);

                            if (resType == typeof(JsonObject))
                            {
                                baseSchema = new JsonSchema { Type = JsonObjectType.Object };
                            }
                            else if (resType == typeof(JsonArray))
                            {
                                baseSchema = new JsonSchema { Type = JsonObjectType.Array };
                            }
                            else if (resType == typeof(JsonNode) || resType == typeof(string) || resType == typeof(object) || finalType == typeof(object))
                            {
                                baseSchema = new JsonSchema { Type = JsonObjectType.String };
                            }
                            else if (IsSimpleType(resType))
                            {
                                baseSchema = generator.Generate(resType.ToContextualType(), resolver);
                            }
                            else if (isArray && IsSimpleType(finalType)) //是数组，又是简单类型
                            {
                                baseSchema = generator.Generate(resType.ToContextualType(), resolver);
                            }
                            else
                            {
                                var componentsVal = generator.Generate(finalType.ToContextualType(), resolver);

                                if (!isArray)
                                {
                                    baseSchema = new JsonSchema
                                    {
                                        Reference = componentsVal
                                    };
                                }
                                else
                                {
                                    baseSchema = new JsonSchema
                                    {
                                        Type = JsonObjectType.Array,
                                        Item = new JsonSchema
                                        {
                                            Reference = componentsVal
                                        }
                                    };
                                }
                                ;
                            }
                        }

                        if (OnResponse == null)
                        {
                            opt.Responses.Add("200", new OpenApiResponse
                            {
                                Schema = baseSchema
                            });
                        }
                        else
                        {
                            var resData = OnResponse.Invoke(baseSchema);
                            opt.Responses.Add("200", new OpenApiResponse
                            {
                                Schema = resData
                            });
                        }
                    }

                    #endregion

                    //请求类型判断
                    string method;
                    if (action.HttpMethod.ToUpper() == "GET")
                    {
                        method = OpenApiOperationMethod.Get;
                    }
                    else
                    {
                        method = OpenApiOperationMethod.Post;
                    }
                    pathItem[method] = opt;
                    opt.Summary = contextMentodType.GetXmlDocsSummary(); //方法描述
                    opt.Description = contextMentodType.GetXmlDocsRemarks().Replace("\n", "</br>"); //方法备注
                    var route = module.RouteName + action.RouteName;
                    if (!string.IsNullOrEmpty(action.PathName))
                    {
                        route += $"/{{{action.PathName}}}";
                    }
                    document.Paths[route] = pathItem;
                }
            }
        }

        private string _apiKey;
        private OpenApiSecurityApiKeyLocation _apiKeyIn;
        public void AddApiKey(string apiKey, OpenApiSecurityApiKeyLocation location = OpenApiSecurityApiKeyLocation.Header)
        {
            _apiKey = apiKey;
            _apiKeyIn = location;
        }

        private bool _addBearer;
        public void AddJwtBearer()
        {
            _addBearer = true;
        }

        private string _loginUrl;
        private string _jsonPath;
        public void AddLogin(string url, string jsonPath)
        {
            _loginUrl = url;
            _jsonPath = jsonPath;
        }

        public void CreateApiJsonFile(string savePath)
        {
            var swaggerFolder = Path.Combine(savePath, "swagger");

            if (!swaggerFolder.EndsWith("/") || !swaggerFolder.EndsWith(@"\"))
            {
                swaggerFolder += Path.DirectorySeparatorChar;
            }

            var apiFolder = $"{swaggerFolder}{Path.DirectorySeparatorChar}api/";

            if (!Directory.Exists(apiFolder))
            {
                Directory.CreateDirectory(apiFolder);
            }

            var urls = new List<dynamic>();

            foreach (var item in groupDict)
            {
                var groupName = item.Key;
                urls.Add(new { name = groupName, url = $"api/{groupName}.json" });
                var document = new OpenApiDocument();
                if (!string.IsNullOrEmpty(_apiKey))
                {
                    document.AddApiKey(_apiKey, _apiKeyIn);
                }

                if (_addBearer)
                {
                    document.AddJwtBearer();
                }

                OnCreateDocument?.Invoke(document);
                InitDocument(document, item.Value);
                var format = Formatting.None;
                if (WriteIndented)
                {
                    format = Formatting.Indented;
                }
                var json = document.ToJson(SchemaType.OpenApi3, format);
                File.WriteAllText($"{apiFolder}{groupName}.json", json, Encoding.UTF8);
            }

            var initJs = """
                window.onload = function () {
                    window.ui = SwaggerUIBundle({
                        urls: @@urls,
                        dom_id: '#swagger-ui',
                        deepLinking: true,
                        presets: [
                            SwaggerUIBundle.presets.apis,
                            SwaggerUIStandalonePreset
                        ],
                        plugins: [
                            SwaggerUIBundle.plugins.DownloadUrl
                        ],
                        layout: "StandaloneLayout",
                        onComplete: function () {
                            var keyName = "@@apiKey";
                            if (keyName == null || keyName == "") {
                                return;
                            }
                            var keyVal = window.localStorage.getItem(keyName);
                            if (keyVal != null && keyVal != "") {
                                window.ui.preauthorizeApiKey(keyName, keyVal);
                            }
                            document.getElementsByClassName('auth-wrapper')[0].addEventListener('click', function (ev) {
                                var target = ev.target || ev.srcElement;
                                if (target.nodeName.toLowerCase() == 'button') {
                                    if (target.children.length > 0) {
                                        return;
                                    }
                                    var btnTxt = target.innerText;
                                    if (btnTxt == "Authorize") {
                                        var rootDiv = document.getElementsByClassName("auth-container")[0];
                                        var formDiv = rootDiv.children[0];
                                        var wrapDiv = formDiv.children[0];
                                        if (keyName != 'Authorization Bearer') {
                                            wrapDiv = wrapDiv.children[0];
                                        }
                                        var input = wrapDiv.lastChild.children[1].children[0];
                                        var inputVal = input.value;
                                        if (inputVal == "") {
                                            return;
                                        }
                                        window.localStorage.setItem(keyName, inputVal);
                                    }
                                    else if (btnTxt == "Logout") {
                                        window.localStorage.removeItem(keyName);
                                    }
                                }
                            });
                        },
                        responseInterceptor: function (res) {
                            var keyName = "@@apiKey";
                            if (keyName != null && keyName != "") {
                                try {
                                    var url = res.url.split('?')[0].toLowerCase();
                                    if (url.endsWith('@@loginUrl'.toLocaleLowerCase())) {
                                        var obj = res.obj;
                                        var val = obj@@jsonPath;
                                        if (val != null && val != "" && val != undefined) {
                                            window.localStorage.setItem(keyName, val);
                                            window.ui.preauthorizeApiKey(keyName, val);
                                        }
                                    }
                                } catch { }
                            }
                            return res;
                        }
                    });
                };
                """;
            if (!string.IsNullOrEmpty(_apiKey))
            {
                initJs = initJs.Replace("@@apiKey", _apiKey);
            }
            else if (_addBearer)
            {
                initJs = initJs.Replace("@@apiKey", "Authorization Bearer");
            }
            else
            {
                initJs = initJs.Replace("@@apiKey", "");
            }

            if (!string.IsNullOrEmpty(_loginUrl))
            {
                initJs = initJs.Replace("@@loginUrl", _loginUrl);
            }
            initJs = initJs.Replace("@@jsonPath", _jsonPath);

            initJs = initJs.Replace("@@urls", JsonConvert.SerializeObject(urls));

            #region 解压zip资源

            var version = "FastApi.Swag.swagger";
            if (Version == FastSwagVersion.V40)
            {
                version += ".zip";
            }
            else
            {
                version += "-v5.zip";
            }

            using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(version);
            using var archive = new ZipArchive(stream);
            archive.ExtractToDirectory(savePath, true);

            #endregion

            File.WriteAllText($"{swaggerFolder}swagger-initializer.js", initJs, Encoding.UTF8);
        }

    }
}
